package com.fowo.api.syncAmazon.core.sync;

import cn.hutool.core.collection.ListUtil;
import com.amazon.spapi.client.ApiException;
import com.amazon.spapi.model.reports.CreateReportSpecification;
import com.amazon.spapi.model.reports.Report;
import com.amazon.spapi.model.reports.ReportDocument;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fowo.api.entity.*;
import com.fowo.api.service.impl.*;
import com.fowo.api.syncAmazon.core.AbstractAmazonSyncData;
import com.fowo.api.syncAmazon.core.ReportApiType;
import com.fowo.api.syncAmazon.entity.ApiDefine;
import com.fowo.api.syncAmazon.entity.ApiRequestLog;
import com.fowo.api.syncAmazon.mapper.AmazonTmpMapper;
import com.fowo.api.syncAmazon.util.AmzDateUtils;
import com.fowo.api.syncAmazon.util.GeneralUtil;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.threeten.bp.OffsetDateTime;

import javax.annotation.Resource;
import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @fileName: SalesStatementSync
 * @Description: 销售统计报告
 * @Author: yyf
 * @Date: 2024/2/2 0002 10:46
 */
@Slf4j
@Component
public class SalesStatementSync extends AbstractAmazonSyncData {
    @Resource
    private TmpSalesStatementServiceImpl tmpSalesStatementService;
    @Resource
    private ShopInfoServiceImpl shopInfoServiceImpl;
    @Resource
    private AmazonTmpMapper amazonTmpMapper;
    private ApiDefine apiDefine = ApiDefine.builder()
            .apiCode("sales_statement")
            .initdate(30)
            .timeInterval(30)
            .timeIntervalType("day").build();

    @Override
    protected ApiDefine setApiDefine() {
        return apiDefine;
    }

    @Override
    protected void requestData() throws Exception {
        // 获取卖家账号信息 并缓存
        String platform = "Amazon";
        this.getAuthority(platform);
        // 所有店铺
        LambdaQueryWrapper<ShopInfo> shopInfosWrapper = new LambdaQueryWrapper<>();
        shopInfosWrapper.eq(ShopInfo::getPlatform,"Amazon")
                .eq(ShopInfo::getSellerAuthStatus,"SQ01");
        List<ShopInfo> shopInfoList = shopInfoServiceImpl.list(shopInfosWrapper);
        if(shopInfoList == null && shopInfoList.size()==0){
            logger.error("暂无Amazon店铺");
            return;
        }
        Map<String, List<ShopInfo>> refreshTokens = shopInfoList.stream()
                .collect(Collectors.groupingBy(ShopInfo::getRefreshToken));

        // 清空临时表
        amazonTmpMapper.deleteAllSalesStatement();

        OffsetDateTime statTimeUTC = AmzDateUtils.getOffsetDateTimeUTC(startTime);
        OffsetDateTime endTimeUTC = AmzDateUtils.getOffsetDateTimeUTC(endTime);

        // 销售统计（所有订单）报告按账号获取，不区分店铺
        for (String refreshToken : refreshTokens.keySet()) {
            ShopInfo shopInfo = refreshTokens.get(refreshToken).get(0);

            //创建报告 -查询参数
            List<String> marketplaceIds = Arrays.asList(shopInfo.getMarketplaceId().split(","));
            CreateReportSpecification body = new CreateReportSpecification();
            body.setReportType(ReportApiType.GET_FLAT_FILE_ALL_ORDERS_DATA_BY_LAST_UPDATE_GENERAL);
            body.setMarketplaceIds(marketplaceIds);
            // 获取拉取的时间区间
            body.setDataStartTime(statTimeUTC);
            body.setDataEndTime(endTimeUTC);

            ReportDocument reportDocument = null;
            try {
                // 第一步 创建报告
                final String reportId = retryCreateReport(shopInfo, body);
                // 第二步 检验报告是否完成
                Report report = retryCheckReport(shopInfo, reportId);
                if(report == null){
                    continue;
                }
                // 第三步 获取报告连接
                reportDocument = getReportDocument(shopInfo,report.getReportDocumentId());
                logger.info(reportDocument.getUrl());
            } catch (ApiException e) {
                apiRequestLog.setErrorMessage("请求与获取报告出现异常："+e);
                apiRequestLog.setStatus(ApiRequestLog.FAIL);
                apiRequestLogService.getBaseMapper().updateById(apiRequestLog);

                throw new RuntimeException(e);
            }

            String compressionAlgorithm = null;
            if(null != reportDocument.getCompressionAlgorithm()){
                compressionAlgorithm = reportDocument.getCompressionAlgorithm().getValue();
            }

            // 记得关闭reader
            BufferedReader reader = null;
            try {
                reader =  this.getAndUnzipReport(reportDocument.getUrl(), compressionAlgorithm);
                download(reader,shopInfo);
            }catch(Exception e){
                apiRequestLog.setErrorMessage("解析与下载报告出现异常："+e);
                apiRequestLog.setStatus(ApiRequestLog.FAIL);
                apiRequestLogService.getBaseMapper().updateById(apiRequestLog);

                throw new RuntimeException(e);
            }finally {
                if(reader != null){
                    reader.close();
                }
            }
        }
    }

    /**
     * 下载报告
     * @throws IOException
     * @throws IllegalArgumentException
     */
    @Override
    protected <T> void download(T readerTmp, ShopInfo shop) throws IOException, IllegalArgumentException {
        // 泛型转换
        BufferedReader reader = null;
        if (readerTmp instanceof BufferedReader) {
            try {
                reader = (BufferedReader) readerTmp;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        int lineNumber = 0;
        String line;
        Map<String, Integer> titleList = new HashMap<String, Integer>();
        List<TmpSalesStatement> list = new ArrayList<>();

        while ((line = reader.readLine()) != null) {
            String[] info = line.split("\t");
            int length = info.length;
            if (lineNumber == 0) {
                for (int i = 0; i < length; i++) {
                    titleList.put(info[i], i);
                }
            } else {
                String orderStatus = (String) getFieldValue(info, "order-status", titleList);
//                if (!orderStatus.equals("Shipped") && !orderStatus.equals("Unshipped") && !orderStatus.equals("Pending")) {
//                    continue;
//                }

                TmpSalesStatement tmp = new TmpSalesStatement();
                tmp.setCreateTime(new Date());

                // 使用getFieldsFromInfo方法获取所有字段的值
                Map<String, Object> fields = this.getFieldsFromInfo(info, titleList);

                tmp.setOrderStatus(orderStatus);
                tmp.setAmazonOrderId((String) fields.get("amazon-order-id"));
                tmp.setMerchantOrderId((String) fields.get("merchant-order-id"));
                String shipCountry = fields.get("ship-country").toString();
                tmp.setPurchaseDate(GeneralUtil.getDatePlus(fields.get("purchase-date").toString(), shipCountry));
                tmp.setLastUpdatedDate(GeneralUtil.getDatePlus(fields.get("last-updated-date").toString(), shipCountry));
                tmp.setFulfillmentChannel((String) fields.get("fulfillment-channel"));
                tmp.setSalesChannel((String) fields.get("sales-channel"));
                tmp.setOrderChannel((String) fields.get("order-channel"));
                tmp.setShipServiceLevel((String) fields.get("ship-service-level"));
                tmp.setProductName((String) fields.get("product-name"));
                tmp.setMsku((String) fields.get("sku"));
                tmp.setAsin((String) fields.get("asin"));
                tmp.setItemStatus((String) fields.get("item-status"));
                tmp.setQuantity((String) fields.get("quantity"));
                tmp.setCurrency((String) fields.get("currency"));
                tmp.setItemPrice(GeneralUtil.getBigDecimal(fields.get("item-price").toString()));
                tmp.setItemTax(GeneralUtil.getBigDecimalValue(fields.get("item-tax").toString()));
                tmp.setShippingPrice(GeneralUtil.getBigDecimalValue(fields.get("shipping-price").toString()));
                tmp.setShippingTax(GeneralUtil.getBigDecimalValue(fields.get("shipping-tax").toString()));
                tmp.setGiftWrapPrice(GeneralUtil.getBigDecimalValue(fields.get("gift-wrap-price").toString()));
                tmp.setGiftWrapTax(GeneralUtil.getBigDecimalValue(fields.get("gift-wrap-tax").toString()));
                tmp.setItemPromotionDiscount(GeneralUtil.getBigDecimalValue(fields.get("item-promotion-discount").toString()));
                tmp.setShipCity((String) fields.get("ship-city"));
                tmp.setShipState((String) fields.get("ship-state"));
                tmp.setShipPostalCode((String) fields.get("ship-postal-code"));
                tmp.setShipCountry(shipCountry);
                tmp.setPromotionIds((String) fields.get("promotion-ids"));
                tmp.setIsBusinessOrder(GeneralUtil.getBooleanValue(fields.get("is-business-order")));
                tmp.setPurchaseOrderNumber((String) fields.get("purchase-order-number"));
                tmp.setPriceDesignation((String) fields.get("price-designation"));
                tmp.setSignatureConfirmationRecommended(GeneralUtil.getBooleanValue(fields.get("signature-confirmation-recommended")));


                list.add(tmp);
            }
            lineNumber++;
        }

        // 记录本次数据同步量
        Integer dataVolume = apiRequestLog.getDataVolume() == null ? 0 : apiRequestLog.getDataVolume();
        apiRequestLog.setDataVolume(dataVolume+list.size());
        logger.debug("保存的数据量："+list.size());
        // 和listing_father做关联
        getIdFromListingFather(list);
        tmpSalesStatementService.saveBatch(list);
        // 删除本次同步的销售统计数据
        List<String> amountOrderIds = list.stream().map(TmpSalesStatement::getAmazonOrderId).distinct().collect(Collectors.toList());
        for (List<String> strings : Lists.partition(amountOrderIds, 900)) {
            amazonTmpMapper.deleteSalesStatementByAOId(strings);
        }
    }
    @Override
    protected void updateOrInsertData() {
        tmpSalesStatementService.getBaseMapper().updateOrInsert();
    }

    @Resource
    private ListingFatherServiceImpl listingFatherService;
    @Resource
    private SellOrderServiceImpl sellOrderService;
    private void getIdFromListingFather(List<TmpSalesStatement> lists){
        if(lists == null || lists.size() == 0){
            return;
        }

        List<SellOrder> sellOrders = new ArrayList<>();
        for (List<TmpSalesStatement> tmpSalesStatementList : ListUtil.partition(lists, 500)) {
            List<String> amazonOrderIds = tmpSalesStatementList.stream().map(TmpSalesStatement::getAmazonOrderId)
                    .distinct().collect(Collectors.toList());
            // 先用amazon_order_id和订单做关联取sid
            List<SellOrder> tmpSellOrder = sellOrderService.getBaseMapper().selectList(Wrappers.lambdaQuery(SellOrder.class)
                    .in(SellOrder::getAmazonOrderId, amazonOrderIds));
            sellOrders.addAll(tmpSellOrder);
        }

        for (SellOrder sellOrder : sellOrders) {
            lists.forEach(r -> {
                if(r.getAmazonOrderId().equals(sellOrder.getAmazonOrderId())){
                    r.setSid(sellOrder.getSid());
                }
            });
        }

        List<ListingFather> listingFather = new ArrayList<>();
        for (List<TmpSalesStatement> tmpSalesStatementList : ListUtil.partition(lists, 500)) {
            List<String> mskus = tmpSalesStatementList.stream().map(TmpSalesStatement::getMsku)
                    .distinct().collect(Collectors.toList());
            List<Long> shopIds = tmpSalesStatementList.stream().map(TmpSalesStatement::getSid)
                    .distinct().collect(Collectors.toList());
            List<ListingFather> tmp = listingFatherService.list(Wrappers.lambdaQuery(ListingFather.class).in(ListingFather::getShop, shopIds)
                    .in(ListingFather::getMsku, mskus));
            listingFather.addAll(tmp);
        }

        for (TmpSalesStatement list : lists) {
            List<ListingFather> collect = listingFather.stream().filter(r -> r.getMsku().equals(list.getMsku()) && r.getShop().equals(list.getSid())).collect(Collectors.toList());
            if (collect != null && collect.size() > 0){
                Optional<ListingFather> exist1 = collect.stream().filter(r -> r.getStatus().equals(1)).findFirst();
                Optional<ListingFather> exist2 = collect.stream().filter(r -> r.getStatus().equals(0)).findFirst();
                if (exist1.isPresent()){
                    list.setInnerLID(exist1.get().getId());
                }else if(exist2.isPresent()){
                    list.setInnerLID(exist2.get().getId());
                }else{
                    list.setInnerLID(collect.get(0).getId());
                }
            }
        }
    }
}
